package com.gitee.feizns.quickstart.spring.expression;

import lombok.NonNull;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.Map;

/**
 * SpEl表达式工具类
 *
 * <pre>{@code
 *     public static void main(String[] args) {
 *         Map<String, Object> map = Maps.of("name", "hello");
 *         System.out.println(parser.parseExpression("#{['name']} world!!!", POUND_SIGN_TEMPLATE).getValue(map));
 *         System.out.println(parser.parseExpression("${['name']} world!!!", DOLLAR_TEMPLATE).getValue(map));
 *         System.out.println(parser.parseExpression("#root['name'] + ' world!!!'").getValue(map));
 *     }
 * }</pre>
 *
 * @link <a href="https://www.jianshu.com/p/e0b50053b5d3">SpEl表达式总结（简书）</a>
 * @link <a href="https://zhuanlan.zhihu.com/p/174786047">玩转Spring中强大的spel表达式！</a>
 * @author feizns
 * @since 2023/2/24
 */
public abstract class SpEl {

    /**
     * 美元模板 '${}'
     */
    public static final ParserContext DOLLAR_TEMPLATE = new ParserContext() {

        @Override
        public boolean isTemplate() {
            return true;
        }

        @Override
        public @NonNull String getExpressionPrefix() {
            return "${";
        }

        @Override
        public @NonNull String getExpressionSuffix() {
            return "}";
        }

    };

    /**
     * 井号模板 '#{}'
     */
    public static final ParserContext POUND_SIGN_TEMPLATE = ParserContext.TEMPLATE_EXPRESSION;

    /**
     * 解析器
     */
    public static final ExpressionParser parser = new SpelExpressionParser();

    /**
     * 编译SpEl表达式
     * @param expression 表达式
     * @return {@link #parser}
     */
    public static Expression parse(String expression) {
        return parser.parseExpression(expression);
    }

    /**
     * 编译SpEl表达式
     * @param expression 表达式
     * @param context {@link ParserContext}
     * @return {@link #parser}
     */
    public static Expression parse(String expression, ParserContext context) {
        return parser.parseExpression(expression, context);
    }

    /**
     * 在指定的上下文中解析数据
     * @param expression 表达式
     * @param root {@link EvaluationContext}
     * @return {@link #parser}
     */
    public static Object execute(String expression, Object root) {
        return parser.parseExpression(expression).getValue(root);
    }

    /**
     * 执行
     * @param expression 表达
     * @param variables 变量列表
     * @return {@link Object }
     */
    public static Object execute(String expression, Map<String, Object> variables) {
        return parser.parseExpression(expression).getValue(context(variables));
    }

    /**
     * 在指定的上下文中解析数据
     * @param expression 表达式
     * @param context 上下文
     * @return {@link #parser}
     */
    public static Object execute(String expression, EvaluationContext context) {
        return parser.parseExpression(expression).getValue(context);
    }

    /**
     * 解析执行
     * @param expression 表达
     * @return {@link Object }
     */
    public static Object execute(String expression) {
        return parser.parseExpression(expression).getValue();
    }

    /**
     * 上下文
     * @param variables 变量
     * @return {@link StandardEvaluationContext }
     */
    public static StandardEvaluationContext context(Map<String, Object> variables) {
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariables(variables);
        return context;
    }

}
